package com.sy.simpleegg.serialport.banknote

import android.util.Log
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.base.BaseController
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.util.MyFunc
import com.sy.simpleegg.util.ByteUtil
import org.cnbleu.serialport.SerialPort
import java.util.Timer
import java.util.TimerTask

abstract class BanknoteBaseController(
    portName: String,
    baudrate: SerialPort.BAUDRATE,
    stopb: SerialPort.STOPB,
    datab: SerialPort.DATAB,
    parity: SerialPort.PARITY,
    speed: Long
):BaseController(portName, baudrate, stopb, datab, parity, speed) {

    private val TAG = javaClass.simpleName

    /**
     * 1元
     */
    private val CNY_1 = "818F40"

    /**
     * 5元
     */
    private val CNY_5 = "818F41"

    /**
     * 10元
     */
    private val CNY_10 = "818F42"

    /**
     * 20元
     */
    private val CNY_20 = "818F43"

    /**
     * 50元
     */
    private val CNY_50 = "818F44"

    /**
     * 100元
     */
    private val CNY_100 = "818F45"

    /**
     * 初始化或者重置
     */
    private val INIT = "808F"

    /**
     * 进钞
     */
    private val IN_MONEY = "81"

    /**
     * 纸钞前缀
     */
    private val MONEY_HEAD_1 = "3D"

    /**
     * 纸钞前缀
     */
    private val MONEY_HEAD_2 = "8F"

    /**
     * 接收完毕
     */
    private val SAVE_MONEY_SUCCESS = "10"

    /**
     * 接收失败
     */
    private val SAVE_MONEY_FAILE = "11"

    /**
     * 结束
     */
    private val FINISH = "292F"

    /**
     * 纸钞校验标记
     */
    private val FLAG_MONEY = "3D"

    /**
     * 使能
     */
    private val ENABLE = "3E"

    /**
     * 禁能
     */
    private val DISABLE = "5E"

    /**
     * 拒钞
     */
    private val REJECTION = "0F"

    /**
     * 暂存
     */
    private val STAGING = "18"

    /**
     * 检测状态
     */
    private val CHECK = "0C"

    /**
     * 重置
     */
    private val RESET = "30"

    /**
     * 进钞 或者 初始化通讯
     */
    private val IN_CASH = "02"

    private var totalMoney = 0L
    private var checkMoney = 0L

    //发送的数据包头
    var sendHeader = 0xaa

    //发送的数据包尾
    var sendTail = 0xab

    //发送进钞指令
    private val sendcommand = 0x08

    //接收确认纸钞成功指令
    private val getcommand = 0x88

    //有紙鈔進入
    private val startcommand = 0x10

    //进钞类型
    private val type = 0x01

    private val LAST_SEND_CMD = ""

    /**
     * 进钞后，是否检测面值
     */
    private var checkCash = false

    /**
     * 纸钞前缀
     */
    private var head = ""

    private var isInit = false

    private var recFinishCount = 0

    private var isClose = true

    private var isSaveMoney = false

    private var timer: Timer? = null
    
    init {
        
    }
    
    override fun onDataReceived(comData: ComData) {
        try {
            if (comData.data.isEmpty()){
                return
            }
            val bytes = comData.data
            var str: String = ByteUtil.bytes2HexStr(bytes)
            logFile("收到纸钞数据:$str")

            if (FINISH == str) {
                checkCash = false
                head = ""
                recFinishCount++
                if (recFinishCount >= 3) {
                    logFile("纸钞机异常，进钞没有校验数据，只收到292F，需要发送重置指令，重新进钞")
                    //重新开始进钞
                    disableOnly()
                    isClose = false
                    val timer = Timer()
                    timer.schedule(object : TimerTask() {
                        override fun run() {
                            if (!isClose) {
                                enableOnly()
                            }
                        }
                    }, 500)
                }
                return
            } else {
                recFinishCount = 0
            }

            if (str.contains("818F")) {
                checkCash = true
            }
            logFile("checkCash:$checkCash isSaveMoney:$isSaveMoney")

            /**
             * 发送接收纸钞后，收到纸钞数据则执行此代码
             */
            if (isSaveMoney) {
                //收到暂存指令响应
                if ("2A" == str) {
                    logFile("允许进钞指令发送后收到暂存响应指令")
                    return
                }
                if (timer != null) {
                    timer!!.cancel()
                    timer = null
                }
                if (SAVE_MONEY_SUCCESS == str) {
                    isSaveMoney = false
                    checkCash = false
                    totalMoney += checkMoney
                    Log.d(TAG, "纸钞机一共收到 $totalMoney 元")
                    getMoney(checkMoney, totalMoney)
                } else if (SAVE_MONEY_FAILE == str) {
                    isSaveMoney = false
                    logFile("纸钞接收失败:$checkCash")
                    checkCash = false
                }
                return
            }

            if (checkCash) {
                Log.d(TAG, "纸钞数据长度:" + str.length)
                if (str.length == 4 || str.length == 6) {
                    str = head + str
                    logFile("收到纸钞最终识别数据:$str")
                    if (isClose) {
                        logFile("纸钞机禁能指令发送后收到纸钞识别数据:$str")
                        rejection()
                        return
                    }
                    when (str) {
                        CNY_1 -> {
                            checkMoney = 1
                            Log.d(TAG, "收到1元纸钞")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CNY_5 -> {
                            checkMoney = 5
                            Log.d(TAG, "收到5元纸钞")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CNY_10 -> {
                            checkMoney = 10
                            Log.d(TAG, "收到10元纸钞")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CNY_20 -> {
                            checkMoney = 20
                            Log.d(TAG, "收到20元纸钞")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CNY_50 -> {
                            checkMoney = 50
                            Log.d(TAG, "收到50元纸钞")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        CNY_100 -> {
                            checkMoney = 100
                            Log.d(TAG, "收到100元纸钞")
                            checkMoneyGetCoin(totalMoney + checkMoney, checkMoney)
                        }

                        else -> {}
                    }
                    return
                } else if (MONEY_HEAD_1 == str) {
                    head = head + str
                    Log.d(TAG, "纸钞 head1=$head")
                    return
                } else if (MONEY_HEAD_2 == str) {
                    head = head + str
                    Log.d(TAG, "纸钞 head2=$head")
                    return
                } else if (IN_MONEY == str) {
                    head = str + head
                    Log.d(TAG, "纸钞 head3=$head")
                    return
                }
            }

            //指令处理

            //指令处理
            if (INIT == str) {
                //初始化通讯指令，安卓板收到后需要发送 02 响应
                initBanknote()
            } else if (IN_MONEY == str) {
                //进钞后，需要校验进钞面值
                checkCash = true
                checkMoney = 0
                head = IN_MONEY
                Log.d(TAG, "纸钞 head4=$head")
            } else if (MONEY_HEAD_1 == str) {
                checkCash = true
                checkMoney = 0
                head = MONEY_HEAD_1
                Log.d(TAG, "纸钞 head5=$head")
            } else if (MONEY_HEAD_2 == str) {
                checkCash = true
                checkMoney = 0
                head = MONEY_HEAD_2
                Log.d(TAG, "纸钞 head6=$head")
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("纸钞机处理响应数据异常：${e.message}")
        }
    }

    override fun cmdTimeout(comData: ComData) {

    }

    /**
     * 初始化通讯
     */
    private fun initBanknote() {
        if (!isInit) {
            isInit = true
            val timer = Timer()
            timer.schedule(object : TimerTask() {
                override fun run() {
                    logFile("发送到纸钞机：$IN_CASH 初始化通讯")
                    sendHexStr(IN_CASH)
                    try {
                        Thread.sleep(200)
                    } catch (e: InterruptedException) {
                        e.printStackTrace()
                    }
                    disable()
                    isInit = false
                }
            }, 200)
        }
    }

    fun startInMoney(isStart: Boolean) {
        if (isStart) {
            enable()
        } else {
            disable()
        }
    }

    fun canSaveMoney(isSave: Boolean) {
        if (isSave) {
            saveMoney()
        } else {
            rejection()
        }
    }

    /**
     * 接收纸钞
     */
    private fun saveMoney() {
        try {
                isSaveMoney = true
                if (timer != null) {
                    timer!!.cancel()
                    timer = null
                }
                timer = Timer()
                timer!!.schedule(object : TimerTask() {
                    override fun run() {
                        logFile("纸钞机发送02指令后未收到响应数据")
                        isSaveMoney = false
                    }
                }, 2000)
                logFile("发送到纸钞机：$IN_CASH 允许进钞")
            sendHexStr(IN_CASH)
        } catch (e: Exception) {
            e.printStackTrace()
            logFile("接收纸钞处理异常：" + e.message)
        }
    }

    fun isSavingMoney(): Boolean {
        return isSaveMoney
    }
    
    private fun sendHexStr(dataHexStr: String){
        try {
            sendData(MyFunc.HexToByteArr(dataHexStr), 500)
        }catch (e: Exception){
            logFile("纸钞机 sendByte 发送指令异常：${e.message}")
        }
    }
    
    private fun disableOnly() {
        logFile("发送到纸钞机-：$DISABLE 禁能")
        sendHexStr(DISABLE)
    }

    private fun enableOnly(){
        logFile("发送到纸钞机-：$ENABLE 使能")
        sendHexStr(ENABLE)
    }

    /**
     * 拒收
     */
    private fun rejection(){
        logFile("发送到纸钞机：$REJECTION 拒收")
        sendHexStr(REJECTION)
    }

    /**
     * 暂存
     */
    private fun staging() {
        logFile("发送到纸钞机：$STAGING 暂存")
        sendHexStr(STAGING)
    }

    /**
     * 使能
     */
    private fun enable() {
        isClose = false
        recFinishCount = 0
        logFile("发送到纸钞机：$ENABLE 使能")
        sendHexStr(ENABLE)
    }

    /**
     * 禁能
     */
    private fun disable() {
        isClose = true
        totalMoney = 0
        logFile("发送到纸钞机：$DISABLE 禁能")
        sendHexStr(DISABLE)
    }

    private fun checkMoneyGetCoin(money: Long, checkMoney: Long) {
        staging()
        //收到纸钞后，检查总金额出币数量是否超过剩余币数
        recieveMoney(money, checkMoney)
    }

    /**
     * 进钞
     * @param checkMoney 当前进钞的面额
     * @param totalMoney 总进钞面额
     */
    abstract fun getMoney(checkMoney: Long, totalMoney: Long)

    /**
     * 校验金额是否超过剩余币数或其他逻辑，根据继承者处理进钞或拒绝
     * @param tempMoney
     * @param checkMoney
     */
    abstract fun recieveMoney(tempMoney: Long, checkMoney: Long)

}